#include "StdAfx.h"
#include "CarrierImpl.h"
#include "Randomizer.h"
//#include "SoundBank.h"
#include "Scale.h"
#include "WaveFormProvider.h"

static Randomizer randomizer;


CarrierImpl::CarrierImpl(void)
{
	frequencyProvider = NULL;
	vocoderListener = NULL;
	soundBank = NULL;
	scale = NULL;
}

CarrierImpl::~CarrierImpl(void)
{
	std::map<WaveForm, WaveFormProvider*>::iterator iterator = waveFormProviders.begin();
	while(iterator!=waveFormProviders.end())
	{
		delete iterator->second;
		iterator++;
	}
	waveFormProviders.clear();
}

void CarrierImpl::Initialize()
{
	AddWaveFormProvider(Random);
	AddWaveFormProvider(Sawtooth);
	AddWaveFormProvider(Sine);
	AddWaveFormProvider(Square);
	AddWaveFormProvider(Triangular);
	AddWaveFormProvider(UserFunc1);
	AddWaveFormProvider(UserFunc2);
	AddWaveFormProvider(UserFunc3);
	AddWaveFormProvider(Freq2);
	AddWaveFormProvider(Freq3);
	AddWaveFormProvider(Freq4);
	AddWaveFormProvider(Freq5);
	AddWaveFormProvider(Freq6);
	AddWaveFormProvider(Freq7);
	AddWaveFormProvider(Freq8);
	AddWaveFormProvider(Freq9);
}
void CarrierImpl::AddWaveFormProvider(WaveForm waveForm)
{
	waveFormProviders[waveForm] = new WaveFormProvider(waveForm, soundBank, 100, 1.0);
}

void CarrierImpl::SetFrequencyProvider(FrequencyProvider* frequencyProvider)
{
	this->frequencyProvider = frequencyProvider;
}
void CarrierImpl::SetVocoderListener(VocoderListener* vocoderListener)
{
	this->vocoderListener = vocoderListener;
}

static WhiteNoiseProvider whiteNoiseProvider;

short* CarrierImpl::CreateCarrierSample(Settings* settings, short* modulatorSample, unsigned int length, std::vector<SampleMarker>* markers)
{	
	if(waveFormProviders.size()==0)
	{
		Initialize();
	}


	unsigned int frequency = frequencyProvider->GetFrequency(modulatorSample, length, markers);
	if(frequency>0)
	{
		if(scale)
		{
			frequency = scale->GetNearest(frequency);
		}		
	}
	UpdateWaveFormProviders(settings, frequency, settings->GetCarrier()->frequencyVariation);
	/*
	else
	{
		mySample.Silence();
		mySample.AddWhiteNoise(1.0);
	}
	*/

	std::vector<SampleDataProvider*> sampleProviders;
	unsigned int modulatorIntensity = settings->GetCarrier()->modulator;
	SampleDataProviderImpl modulatorProvider(modulatorSample, modulatorIntensity);
	if(modulatorIntensity>0)
	{		
		sampleProviders.push_back(&modulatorProvider);
	}
	std::map<WaveForm, WaveFormProvider*>::iterator iterator = waveFormProviders.begin();
	while(iterator!=waveFormProviders.end())
	{
		sampleProviders.push_back(iterator->second);
		iterator++;
	}

	//add white noise if applicable
	int whiteNoise = settings->GetCarrier()->whiteNoise;
	if(whiteNoise)
	{
		whiteNoiseProvider.intensity = whiteNoise;
		sampleProviders.push_back(&whiteNoiseProvider);
	}



	//TODO - add external providers

	mySample.Mix(sampleProviders, length);
	ApplyStopConsonants(modulatorSample, mySample.GetData(), length, markers);
	return mySample.GetData();
}

static int intensityVariation = 0;
static void updateWaveFormProvider(WaveFormProvider* provider, double intensity, unsigned int frequency, int frequencyVariation)
{
	unsigned int nextIntensity = (unsigned int)(intensity + randomizer.NextInt(-intensityVariation, intensityVariation));
	if(nextIntensity<0) 
		nextIntensity = 0;
	provider->intensity = nextIntensity;
	int offset = randomizer.NextInt(-frequencyVariation, frequencyVariation);
	if(frequency==0)
		frequency = provider->frequency;
	provider->frequency = frequency + offset;
}

void CarrierImpl::UpdateWaveFormProviders(Settings* settings, unsigned int frequency, int frequencyVariation)
{
	Settings::CarrierSettings* csettings = settings->GetCarrier();
	intensityVariation = csettings->intensityVariation;
	updateWaveFormProvider(waveFormProviders[Random], csettings->random, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[Sawtooth], csettings->sawtooth, frequency, frequencyVariation);	
	updateWaveFormProvider(waveFormProviders[Sine], csettings->sine, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[Square], csettings->square, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[Triangular], csettings->triangular, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[UserFunc1], csettings->function1, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[UserFunc2], csettings->function2, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[UserFunc3], csettings->function3, frequency, frequencyVariation);
	updateWaveFormProvider(waveFormProviders[Freq2], csettings->freq2, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq3], csettings->freq3, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq4], csettings->freq4, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq5], csettings->freq5, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq6], csettings->freq6, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq7], csettings->freq7, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq8], csettings->freq8, frequency, 0);
	updateWaveFormProvider(waveFormProviders[Freq9], csettings->freq9, frequency, 0);
}